package fr.babos.core.bundle
{
	/**
	 * Les imports
	 */
	import flash.display.DisplayObjectContainer;
	import flash.events.Event;
	import fr.babos.core.bootstrap.Bootstrap;
	import fr.babos.core.bootstrap.IBootstrap;
	import fr.babos.core.errors.BabosError;
	import fr.babos.core.masters.IMasterDisplayObject;
	import fr.babos.core.masters.MasterSprite;
	import fr.babos.core.mvc.IController;
	import fr.babos.core.roles.IEngine;
	import org.osflash.signals.DeluxeSignal;
	import org.osflash.signals.events.GenericEvent;
	import org.osflash.signals.IDispatcher;
	import org.osflash.signals.ISignal;
	
	/**
	 * @author ZoulouX
	 */
	public class Bundle implements IBundle
	{
		/**
		 * Si on doit l'initialiser automatiquement à l'ajout sur la scène
		 */
		protected var _autoInit							:Boolean;
		
		/**
		 * Si on doit disposer automatiquement à la suppression du clip
		 */
		protected var _autoDispose						:Boolean;
		
		/**
		 * Si le bundle est démarré
		 */
		protected var _started							:Boolean;
		
		/**
		 * Si le bundle est prêt
		 */
		protected var _ready							:Boolean;
		
		/**
		 * Lorsque le bundle est prêt
		 */
		protected var _onReady							:DeluxeSignal;
		
		/**
		 * Lorsque le bundle démarre
		 */
		protected var _onTurningOn						:DeluxeSignal;
		
		/**
		 * Lorsque le bundle a démarré
		 */
		protected var _onTurnedOn						:DeluxeSignal;
		
		/**
		 * Lorsque le bundle s'arrête
		 */
		protected var _onTurningOff						:DeluxeSignal;
		
		/**
		 * Lorsque le bundle s'est arrêté
		 */
		protected var _onTurnedOff						:DeluxeSignal;
		
		/**
		 * Le bootstrap
		 */
		protected var _bootstrap						:IBootstrap;
		
		/**
		 * Le conteneur visuel (contient les vues)
		 */
		protected var _viewContainer					:DisplayObjectContainer;
		
		
		
		/**
		 * Si le bundle est démarré
		 */
		public function get started ():Boolean 
		{
			return _started;
		}
		
		/**
		 * Si le bundle est prêt
		 */
		public function get ready ():Boolean 
		{
			return _ready;
		}
		
		/**
		 * Lorsque le bundle est prêt
		 */
		public function get onReady ():ISignal 
		{
			return _onReady;
		}
		
		/**
		 * Lorsque le bundle démarre
		 */
		public function get onTurningOn ():ISignal 
		{
			// Initialiser le signal à la demande
			if (_onTurningOn == null)
				_onTurningOn = new DeluxeSignal(this);
			
			return _onTurningOn;
		}
		
		/**
		 * Lorsque le bundle a démarré
		 */
		public function get onTurnedOn ():ISignal 
		{
			// Initialiser le signal à la demande
			if (_onTurnedOn == null)
				_onTurnedOn = new DeluxeSignal(this);
			
			return _onTurnedOn;
		}
		
		/**
		 * Lorsque le bundle s'arrête
		 */
		public function get onTurningOff ():ISignal 
		{
			// Initialiser le signal à la demande
			if (_onTurnedOn == null)
				_onTurnedOn = new DeluxeSignal(this);
			
			return _onTurningOff;
		}
		
		/**
		 * Lorsque le bundle s'est arrêté
		 */
		public function get onTurnedOff ():ISignal 
		{
			// Initialiser le signal à la demande
			if (_onTurnedOff == null)
				_onTurnedOff = new DeluxeSignal(this);
			
			return _onTurnedOff;
		}
		
		/**
		 * Le bootstrap associé
		 */
		public function get bootstrap ():IBootstrap { return _bootstrap; }
		public function set bootstrap (value:IBootstrap):void 
		{
			// Interdire les bootstraps nulls
			if (value == null)
			{
				// Interdire
				throw new BabosError("Bundle.bootstrap", "Can't set a null bootstrap.");
			}
			else
			{
				// Enregistrer
				_bootstrap = value;
			}
		}
		
		/**
		 * Le conteneur visuel (contient les vues)
		 */
		public function get viewContainer ():DisplayObjectContainer { return _viewContainer; }
		public function set viewContainer (value:DisplayObjectContainer):void 
		{
			// Interdire les containers nulls
			if (value == null)
			{
				// Interdire
				throw new BabosError("Bundle.viewContainer", "Can't set a null viewContainer.");
			}
			else
			{
				// Enregistrer
				_viewContainer = value;
			}
		}
		
		
		/**
		 * Le constructeur
		 * @param	pParentContainer : Le container parent dans lequel ajouter automatiquement le viewContainer (optionnel)
		 * @param	pAutoInit : Initialiser automatiquement lorsque le viewContainer est ajouté
		 * @param	pAutoDispose : Disposer automatiquement lorsque le viewContainer est supprimé
		 */
		public function Bundle (pParentContainer:DisplayObjectContainer = null, pAutoInit:Boolean = true, pAutoDispose:Boolean = true)
		{
			// AutoInit et autoDispose
			_autoInit = pAutoInit;
			_autoDispose = pAutoDispose;
			
			// Initialiser la vue et le bootstrap
			initViewContainer();
			initBootstrap();
			
			// Initialiser le layout
			initLayout();
			
			// Initialiser les commandes et les dépendances
			initDependences();
			initCommands();
			
			// Vérifier si on a un container
			if (_viewContainer == null)
			{
				// Pas de container = erreur
				throw new BabosError("Bundle.bundle", "_viewContainer can't be null, set an IMasterDisplayObject via initViewContainer.");
			}
			else
			{
				// Ecouter lorsque le container est prêt et supprimé
				_viewContainer.addEventListener(Event.ADDED_TO_STAGE, viewContainerAddedHandler);
				_viewContainer.addEventListener(Event.REMOVED_FROM_STAGE, viewContainerAddedHandler);
			}
			
			// Ajouter automatiquement si on a un parent
			if (pParentContainer != null)
				pParentContainer.addChild(_viewContainer);
		}
		
		/**
		 * Initialiser le layout
		 */
		protected function initLayout ():void
		{
			
		}
		
		/**
		 * La vue est ajoutée
		 */
		protected function viewContainerAddedHandler (event:Event = null):void
		{
			// Supprimer l'écoute d'event
			if (_viewContainer != null)
				_viewContainer.removeEventListener(Event.ADDED_TO_STAGE, viewContainerAddedHandler);
			
			// Si autoInit, on init
			if (_autoInit)
				init();
		}
		
		/**
		 * La vue est supprimée
		 */
		protected function viewContainerRemovedHandler (event:Event):void
		{
			// Supprimer l'écoute d'event
			if (_viewContainer != null)
				_viewContainer.removeEventListener(Event.REMOVED_FROM_STAGE, viewContainerRemovedHandler);
			
			// Si autoDispose, on dispose
			if (_autoDispose)
				dispose();
		}
		
		/**
		 * Initialiser le container de vue spécifique
		 */
		protected function initViewContainer ():void
		{
			// Créer le container concrêt par défaut
			_viewContainer = new MasterSprite();
		}
		
		/**
		 * Initialiser le bootstrap spécifique
		 */
		protected function initBootstrap ():void
		{
			// Créer le bootstrap concrêt par défaut
			_bootstrap = new Bootstrap(_viewContainer as DisplayObjectContainer);
		}
		
		/**
		 * Initialiser les dépendences
		 */
		protected function initDependences ():void
		{
			
		}
		
		/**
		 * Initialiser les commandes
		 */
		protected function initCommands ():void
		{
			
		}
		
		/**
		 * Initialisation du bundle (le container est ajoutée à la scène)
		 */
		public function init ():void 
		{
			
		}
		
		/**
		 * Dispatcher une notification engine
		 */
		protected function dispatchEngineSignal (pSignal:ISignal):void
		{
			// Dispatcher avec un event si le signal existe
			if (pSignal != null)
				(pSignal as IDispatcher).dispatch(new GenericEvent());
		}
		
		/**
		 * Démarrage du bundle
		 */
		public function turnOn ():void 
		{
			// Démarré
			_started = true;
			
			// Dispatcher directement (ne pas faire de super pour comportement différent)
			dispatchEngineSignal(_onTurningOn);
			dispatchEngineSignal(_onTurnedOn);
		}
		
		/**
		 * Arrêt du bundle
		 */
		public function turnOff ():void 
		{
			// Arrêté
			_started = false;
			
			// Dispatcher directement (ne pas faire de super pour comportement différent)
			dispatchEngineSignal(_onTurningOff);
			dispatchEngineSignal(_onTurnedOff);
		}
		
		/**
		 * Disposer
		 */
		public function dispose ():void
		{
			// Désactiver les signaux
			_onTurningOn.removeAll();
			_onTurnedOn.removeAll();
			_onTurningOff.removeAll();
			_onTurnedOff.removeAll();
			
			// Virer les signaux
			_onTurningOn = null;
			_onTurnedOn = null;
			_onTurningOff = null;
			_onTurnedOff = null;
			
			// Si on a un bootstrap
			if (_bootstrap != null)
				_bootstrap.dispose();
			
			// Relayer
			super.dispose();
		}
	}
}